///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef _Image_H__
#define _Image_H__

#include "OgrePrerequisites.h"
#include "OgreCommon.h"
#include "OgrePixelFormat.h"
#include "OgreDataStream.h"

namespace Ogre {
	
	

    enum ImageFlags
    {
        IF_COMPRESSED = 0x00000001,
        IF_CUBEMAP    = 0x00000002,
        IF_3D_TEXTURE = 0x00000004
    };
    
	class _OgreExport Image : public MemAlloc_General
    {
    public:
    	typedef Ogre::Box Box;
    	typedef Ogre::Rect Rect;
    public:
        
        Image();
        
        Image( const Image &img );

        
        virtual ~Image();

        
        Image & operator = ( const Image & img );

        
        Image & flipAroundY();

                         
        Image & flipAroundX();

        
		Image& loadDynamicImage( uchar* data, size_t width, size_t height, 
							size_t depth,
							 PixelFormat format, bool autoDelete = false, 
							 size_t numFaces = 1, size_t numMipMaps = 0);
		
		
 		Image& loadDynamicImage( uchar* data, size_t width,
								 size_t height, PixelFormat format)
		{
			return loadDynamicImage(data, width, height, 1, format);
		}
		
        Image & loadRawData( 
            DataStreamPtr& stream, 
            size_t width, size_t height, size_t depth,
            PixelFormat format,
			size_t numFaces = 1, size_t numMipMaps = 0);
        
        Image & loadRawData( 
            DataStreamPtr& stream, 
            size_t width, size_t height, 
            PixelFormat format )
		{
			return loadRawData(stream, width, height, 1, format);
		}

        
        Image & load( const String& filename, const String& groupName );

        
		Image & load(DataStreamPtr& stream, const String& type = StringUtil::BLANK );

		
		Image & loadTwoImagesAsRGBA(const String& rgbFilename, const String& alphaFilename,
			const String& groupName, PixelFormat format = PF_BYTE_RGBA);

		
		Image & loadTwoImagesAsRGBA(DataStreamPtr& rgbStream, DataStreamPtr& alphaStream, PixelFormat = PF_BYTE_RGBA,
			const String& rgbType = StringUtil::BLANK, const String& alphaType = StringUtil::BLANK);

		
		Image & combineTwoImagesAsRGBA(const Image& rgb, const Image& alpha, PixelFormat format = PF_BYTE_RGBA);

        
        
        void save(const String& filename);

		
		DataStreamPtr encode(const String& formatextension);

		
        uchar* getData(void);

        
        const uchar * getData() const;       

        
        size_t getSize() const;

        
        size_t getNumMipmaps() const;

        
        bool hasFlag(const ImageFlags imgFlag) const;

        
        size_t getWidth(void) const;

        
        size_t getHeight(void) const;

        
        size_t getDepth(void) const;
		
		
		size_t getNumFaces(void) const;

        
        size_t getRowSpan(void) const;

        
        PixelFormat getFormat() const;

        
        uchar getBPP() const;

        
        bool getHasAlpha() const;
		
		
        static void applyGamma( uchar *buffer, Real gamma, size_t size, uchar bpp );

        /**
         * Get colour value from a certain location in the image. The z coordinate
         * is only valid for cubemaps and volume textures. This uses the first (largest)
         * mipmap.
         */
        ColourValue getColourAt(size_t x, size_t y, size_t z) const;
        
        /**
         * Set colour value at a certain location in the image. The z coordinate
         * is only valid for cubemaps and volume textures. This uses the first (largest)
         * mipmap.
         */
        void setColourAt(ColourValue const &cv, size_t x, size_t y, size_t z);

        /**
         * Get a PixelBox encapsulating the image data of a mipmap
         */
        PixelBox getPixelBox(size_t face = 0, size_t mipmap = 0) const;

		/// Delete all the memory held by this image, if owned by this image (not dynamic)
		void freeMemory();

		enum Filter
		{
			FILTER_NEAREST,
			FILTER_LINEAR,
			FILTER_BILINEAR,
			FILTER_BOX,
			FILTER_TRIANGLE,
			FILTER_BICUBIC
		};
		
		static void scale(const PixelBox &src, const PixelBox &dst, Filter filter = FILTER_BILINEAR);
		
		
		void resize(ushort width, ushort height, Filter filter = FILTER_BILINEAR);
		
        // Static function to calculate size in bytes from the number of mipmaps, faces and the dimensions
        static size_t calculateSize(size_t mipmaps, size_t faces, size_t width, size_t height, size_t depth, PixelFormat format);

		/// Static function to get an image type string from a stream via magic numbers
		static String getFileExtFromMagic(DataStreamPtr stream);

    protected:
        // The width of the image in pixels
	size_t mWidth;
        // The height of the image in pixels
	size_t mHeight;
        // The depth of the image
	size_t mDepth;
        // The size of the image buffer
	size_t mBufSize;
        // The number of mipmaps the image contains
	size_t mNumMipmaps;
        // Image specific flags.
	int mFlags;

        // The pixel format of the image
	PixelFormat mFormat;

        // The number of bytes per pixel
	uchar mPixelSize;
	uchar* mBuffer;

		// A bool to determine if we delete the buffer or the calling app does
		bool mAutoDelete;
    };

	typedef vector<Image*>::type ImagePtrList;
	typedef vector<const Image*>::type ConstImagePtrList;

	
	

} // namespace

#endif
